﻿using System;
using System.ComponentModel;
using System.Reflection;
using System.Text;
using System.Web.UI;
using JQuery.WebKit.Common.Extenstions;
using JQuery.WebKit.Common.Utilities;
using JQuery.WebKit.WebCommon.Attributes;
using JQuery.WebKit.WebCommon.Javascript;

namespace JQuery.WebKit.WebCommon
{
    public static class Extensions
    {
        public static void SetDefaultPropertyValues(this object componentInstance)
        {
            if (componentInstance == null)
            {
                throw new ArgumentNullException("componentInstance");
            }
            PropertyInfo[] props = componentInstance.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo info in props)
            {
                DefaultValueAttribute defValAttr = (DefaultValueAttribute)Reflection.GetAttribute(componentInstance, info, typeof(DefaultValueAttribute));
                if (defValAttr == null)
                {
                    JavaScriptAttribute defJsValAttr = (JavaScriptAttribute)Reflection.GetAttribute(componentInstance, info, typeof(DefaultValueAttribute));
                    if (defJsValAttr == null)
                    {
                        continue;
                    }
                    info.SetValue(componentInstance, defJsValAttr.DefaultValue, null);
                    continue;
                }

                info.SetValue(componentInstance, defValAttr.Value, null);
            }
        }

        public static bool IsDefault(this object componentInstance, string propertyName)
        {
            if (componentInstance == null)
            {
                throw new ArgumentNullException("componentInstance");
            }
            PropertyInfo property = componentInstance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
            if (property == null)
            {
                throw new ArgumentException("Invalid property name.", "propertyName");
            }
            object val = property.GetValue(componentInstance, null);
            DefaultValueAttribute defValAttr = (DefaultValueAttribute)Reflection.GetAttribute(componentInstance, propertyName, typeof(DefaultValueAttribute));
            if (defValAttr == null)
            {
                JavaScriptAttribute defJsValAttr = (JavaScriptAttribute)Reflection.GetAttribute(componentInstance, propertyName, typeof(DefaultValueAttribute));
                if (defJsValAttr == null)
                {
                    return property.PropertyType.IsDefaultValue(val);
                }
                else
                {
                    return defJsValAttr.DefaultValue != null ? defJsValAttr.DefaultValue.Equals(val) : defJsValAttr.DefaultValue == val;
                }
            }
            else
            {
                return defValAttr.Value != null ? defValAttr.Value.Equals(val) : defValAttr.Value == val;
            }
        }

        public static string GetJSProperties(this object componentInstance, string category)
        {
            if (componentInstance == null)
            {
                throw new ArgumentNullException("componentInstance");
            }
            PropertyInfo[] props = componentInstance.GetType().GetFilteredProperties(BindingFlags.Public | BindingFlags.Instance);
            StringBuilder sb = new StringBuilder();
            int count = 0;
            string val = string.Empty;
            foreach (PropertyInfo info in props)
            {
                val = info.GetJSPropertyValue(componentInstance, category);
                if (string.IsNullOrEmpty(val))
                {
                    continue;
                }
                sb.AppendFormat("{0}, ", val);
                count++;
            }

            if (count > 0)
            {
                return string.Format("{{ {0} }}", sb.ToString().Substring(0, sb.ToString().Length - 2));
            }
            else
            {
                return "null";
            }
        }

        public static string GetJSPropertyValue(this PropertyInfo propertyInfo, object objectInstance)
        {
            return propertyInfo.GetJSPropertyValue(objectInstance, null);
        }

        public static string GetJSPropertyValue(this PropertyInfo propertyInfo, object objectInstance, string category)
        {
            string val = null;

            JavaScriptAttribute jsAtt = (JavaScriptAttribute)objectInstance.GetAttribute(propertyInfo, typeof(JavaScriptAttribute));
            if (jsAtt == null)
            {
                return null;
            }

            if (jsAtt.Category != category)
            {
                return null;
            }

            object propValue = propertyInfo.GetValue(objectInstance, null);
            if (propValue is Control)
            {
                propValue = (propValue as Control).ClientID;
            }
            object defVal = jsAtt.DefaultValue;

            if (propertyInfo.PropertyType.IsDefaultValue(propValue))
            {
                if (defVal != null)
                {
                    propValue = defVal;
                }
                else
                {
                    return null;
                }
            }

            if (string.IsNullOrEmpty(jsAtt.Name))
            {
                val = propValue.ToJSString();
            }
            else
            {
                val = string.Format("{0}: {1}", jsAtt.Name, propValue.ToJSString());
            }

            return val;
        }

        private static bool IsDefaultValue(this Type type, object value)
        {
            object defVal = GetDefault(type);
            return defVal != null ? defVal.Equals(value) : defVal == value;
        }

        public static object GetDefault(this Type type)
        {
            if (type.IsValueType)
            {
                return Activator.CreateInstance(type);
            }
            return typeof(Extensions).GetMethod("GetDefaultImp").MakeGenericMethod(type).Invoke(null, new Type[0]);
        }

        public static T GetDefaultImp<T>()
        {
            return default(T);
        }
    }
}
